#ifdef _WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/gl.h>	
#include <OpenGL/glu.h>	
#else
#include <GL/gl.h>	
#include <GL/glu.h>	
#endif
#include "simple_gl.h"
#include "SDL.h"

FT_Library GL_FTLibrary;
SDL_Rect **modes;
int num_video_modes = 0;

long Timer_GetTicks() {
	return SDL_GetTicks();
}

void initGL(int xRes, int yRes) {
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//	glClearDepth(1.0);
//	glDepthFunc(GL_LESS);
//	glEnable(GL_DEPTH_TEST);
	//glShadeModel(GL_SMOOTH);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	resizeGL(xRes, yRes);
}

void resizeGL(int xRes, int yRes){
	glViewport(0, 0, xRes, yRes);
	//gluPerspective(45.0f,(GLfloat)xRes/(GLfloat)yRes,0.1f,100.0f);
	glOrtho(0.0f,1.0,(float)yRes/(float)xRes,0.0f,-1.0f,1.0f);
	glMatrixMode(GL_MODELVIEW);
}

int GL_Init(int xRes, int yRes, char isFullscreen, char *caption) {
	

	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
		fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
		return 0;
	}
	
	if(isFullscreen == 0) {
		if ( SDL_SetVideoMode(xRes, yRes, 0, SDL_OPENGL) == NULL ) {
			fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
			SDL_Quit();
			return 0;
		}
	} else {
		if ( SDL_SetVideoMode(xRes, yRes, 0, SDL_OPENGL|SDL_FULLSCREEN) == NULL ) {
			fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
			SDL_Quit();
			return 0;
		}
	}
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
	SDL_ShowCursor(SDL_DISABLE);
	SDL_WM_SetCaption(caption , NULL);
	initGL(xRes,yRes);

	int i;
	modes=SDL_ListModes(NULL, SDL_FULLSCREEN);
	for(i=0;modes[i];++i) {
		num_video_modes++;
	}

	
	FT_Init_FreeType(&GL_FTLibrary);
	
	return 1;
}

void GL_SetVideoMode(int video_mode_index, int fullscreen) {
	if(fullscreen == 0) {
		SDL_SetVideoMode(modes[video_mode_index]->w, modes[video_mode_index]->h, 0, SDL_OPENGL);
	} else {
		SDL_SetVideoMode(modes[video_mode_index]->w, modes[video_mode_index]->h, 0, SDL_OPENGL|SDL_FULLSCREEN);
	}
	initGL(modes[video_mode_index]->w,modes[video_mode_index]->h);
}

int GL_GetNumVideoModes() {
	return num_video_modes;
}

int GL_GetModeWidth(int modenum) {
	return modes[modenum]->w;
}

int GL_GetModeHeight(int modenum) {
	return modes[modenum]->h;
}

void GL_Shutdown(){
	SDL_Quit();
}


void GL_BeginRender() {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	//glBegin(GL_TRIANGLES);

}

void GL_EndRender() {
	//glEnd();			
	glFinish();
  	SDL_GL_SwapBuffers();
}

GL_color GL_RGBA_to_Float(GL_color_RGBA color) {
	GL_color new_color;
	new_color.r = color.r/255.0f;
	new_color.g = color.g/255.0f;
	new_color.b = color.b/255.0f;
	new_color.a = color.a/255.0f;
	return new_color;
}

void GL_CreateFont2(char *filename, GL_font2 *font) {
	FT_New_Face(GL_FTLibrary, filename, 0, &font->face );
}

int GL_LoadImage(char *filename, GL_image *targetImage) {
	unsigned long result, width, height;
	GLuint texName;
	char *image;
	result = pngLoad(filename, &width, &height, &image);
	if (result == 0)
		return 0;
	glGenTextures(1, &texName);
	glBindTexture(GL_TEXTURE_2D, texName);
//	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
	GL_image newImage = {width, height, texName};
	*targetImage = newImage;
}

void GL_DrawTintedImage(GL_image *image, float x, float y, float w, float h, float rotation, GL_color_RGBA c1) {
	GL_color _c1 = GL_RGBA_to_Float(c1);
	glColor4f(_c1.r, _c1.g, _c1.b, _c1.a);
	glPushMatrix();
	glTranslatef(x,y,0.0f);
	
	glEnable (GL_TEXTURE_2D);
	glBindTexture (GL_TEXTURE_2D, image->tex_index);
	glRotatef(rotation, 0.0f, 0.0f, 1.0f);
	glBegin(GL_QUADS);
	glTexCoord2f (0.0f,1.0f);
	glVertex2f(0, 0);
	glTexCoord2f (1.0f,1.0f);
	glVertex2f(0+w,0);
	glTexCoord2f (1.0f,0.0f);
	glVertex2f(0+w, 0+h);
	glTexCoord2f (0.0f,0.0f);
	glVertex2f(0, 0+h);
	glEnd();
	glPopMatrix();
	glDisable(GL_TEXTURE_2D);
}

void GL_DrawZImage(GL_image *image, float x, float y, float w, float h, float rotation, float z) {
	glPushMatrix();
	glTranslatef(0.0f,0.0f,z);
	GL_DrawImage(image, x, y, w, h,rotation);
	glPopMatrix();
}
	
void GL_DrawImage(GL_image *image, float x, float y, float w, float h, float rotation) {
	
	float w2 = w/2.0f;
	float h2 = h/2.0f;
	
	glPushMatrix();
	glTranslatef(x+w2,y+h2,0.0f);
	
	glEnable (GL_TEXTURE_2D);
	glColor3f(1.0f, 1.0f, 1.0f);
	glBindTexture (GL_TEXTURE_2D, image->tex_index);
	glRotatef(rotation, 0.0f, 0.0f, 1.0f);

	
	glBegin(GL_QUADS);
	glTexCoord2f (0.0f,1.0f);
	glVertex2f(0.0-w2, 0.0-h2);
	glTexCoord2f (1.0f,1.0f);
	glVertex2f(0.0+w2,0.0-h2);
	glTexCoord2f (1.0f,0.0f);
	glVertex2f(0.0+w2, 0.0+h2);
	glTexCoord2f (0.0f,0.0f);
	glVertex2f(0.0-w2, 0.0+h2);
	glEnd();
	glPopMatrix();
	glDisable(GL_TEXTURE_2D);
}

void GL_DrawLabel(GL_label *label, float size, float x, float y) {
	float w = size;
	float h = size;
	float w2 = w/2.0f;
	float h2 = h/2.0f;
	
	glPushMatrix();
	glTranslatef(x+w2,y+h2,0.0f);
	
	glEnable (GL_TEXTURE_2D);
	glColor4f(label->color.r, label->color.g, label->color.b, label->color.a);
	glBindTexture (GL_TEXTURE_2D, label->tex_index);
	//glRotatef(rotation, 0.0f, 0.0f, 1.0f);

	
	glBegin(GL_QUADS);
	glTexCoord2f (0.0f,0.0f);
	glVertex2f(0.0-w2, 0.0-h2);
	glTexCoord2f (1.0f,0.0f);
	glVertex2f(0.0+w2,0.0-h2);
	glTexCoord2f (1.0f,1.0f);
	glVertex2f(0.0+w2, 0.0+h2);
	glTexCoord2f (0.0f,1.0f);
	glVertex2f(0.0-w2, 0.0+h2);
	glEnd();
	glPopMatrix();
	glDisable(GL_TEXTURE_2D);

}

int GL_GetTextWidth(GL_font2 *font, char *text, int size) {
	FT_Vector delta;
	FT_UInt previous;
	FT_UInt glyph_index;
	FT_GlyphSlot slot = font->face->glyph;
	FT_Set_Pixel_Sizes(font->face, 0,  size);
	int i,width = 0;
	
	for(i=0; i< strlen(text);i++)
	{
		glyph_index = FT_Get_Char_Index( font->face, text[i] );
		if(previous && glyph_index) {
			FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
			width += delta.x >> 6;
		}
		FT_Load_Glyph( font->face, glyph_index, FT_LOAD_DEFAULT );
		FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL );
		width += slot->advance.x >> 6;
	}

	// +5 pixels safety zone :)
	return width+5;
}

int GL_GetOptimalTextSize(GL_font2 *font, char *text, int texRes) {
	int textSize = 1;
	while(GL_GetTextWidth(font, text, textSize) < texRes) {
		textSize++;
	}
	return textSize-1;
}

void GL_SetLabelText(GL_label *label, char *text) {
	int i, j;
	int penX = 0;
	int xoff = 0;
	int x,y;
	FT_Vector delta;
	FT_UInt previous;
	FT_UInt glyph_index;
	FT_GlyphSlot slot = label->font->face->glyph;
	FT_Set_Pixel_Sizes(label->font->face, 0,  label->size);

	// create an openGL texture and our memory buffer
	GLbyte *refData = malloc(((label->textureSize * label->textureSize)* 4 * sizeof(unsigned char)));
	memset(refData, 0, ((label->textureSize * label->textureSize)* 4 * sizeof(unsigned char)));
	
	// copy the freetype data into the texture
	for(i=0; i< strlen(text);i++)
	{
		glyph_index = FT_Get_Char_Index( label->font->face, text[i] );
		if(previous && glyph_index) {
			FT_Get_Kerning(label->font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
			penX += delta.x >> 6;
		}
		FT_Load_Glyph(label->font->face, glyph_index, FT_LOAD_DEFAULT );
		FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL );
		
		int lineoffset = ((label->size-slot->bitmap_top) * (label->textureSize*4));
		xoff = ((penX + slot->bitmap_left)*4);
		for(j = 0; j < ((slot->bitmap.width * slot->bitmap.rows)); j++) {
	
			if(!(j%slot->bitmap.width) && j !=0)
				lineoffset += (label->textureSize*4)-(slot->bitmap.width * 4);

			refData[xoff+lineoffset] = 255;
			refData[xoff+lineoffset+1] =  255;
			refData[xoff+lineoffset+2] =  255;
			refData[xoff+lineoffset+3] =  slot->bitmap.buffer[j];
			xoff += 4;
		}
		
		penX += slot->advance.x >> 6;
		previous = glyph_index;
	}

	// now create the actual texture data and then free our buffer
	glGenTextures( 1, &label->tex_index);
    	glBindTexture(GL_TEXTURE_2D, label->tex_index);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	
	glTexImage2D(GL_TEXTURE_2D, 0, 4, label->textureSize, label->textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, refData);	
	free(refData);
}

void GL_CreateLabel(GL_label *label, GL_font2 *font, char *text, int texRes, int texSize, GL_color_RGBA c1) {
	label->color = GL_RGBA_to_Float(c1);
	label->size = texSize;
	label->textureSize = texRes;
	label->font = font;
	
	GL_SetLabelText(label, text);
	
}

void GL_Rect(float x, float y, float w, float h, GL_color_RGBA c1, float rotation) {
	GL_color _c1 = GL_RGBA_to_Float(c1);
	glColor4f(_c1.r, _c1.g, _c1.b, _c1.a);

	glPushMatrix();
	glTranslatef(x,y,0.0f);
	glRotatef(rotation, 0.0f, 0.0f, 1.0f);
	glBegin(GL_QUADS);
	glVertex2f(0, 0);
	glVertex2f(0+w,0);
	glVertex2f(0+w, 0+h);
	glVertex2f(0, 0+h);
	glEnd();
	glPopMatrix();
}


void GL_VerticalGradientRect(float x, float y, float w, float h, GL_color_RGBA c1, GL_color_RGBA c2) {
	GL_color _c1 = GL_RGBA_to_Float(c1);
	GL_color _c2 = GL_RGBA_to_Float(c2);
	
	glBegin(GL_QUADS);
	glColor4f(_c1.r, _c1.g, _c1.b, _c1.a);
	glVertex2f(x, y);
	glColor4f(_c2.r, _c2.g, _c2.b, _c2.a);
	glVertex2f(x+w,y);
	glColor4f(_c2.r, _c2.g, _c2.b, _c2.a);
	glVertex2f(x+w, y+h);
	glColor4f(_c1.r, _c1.g, _c1.b, _c1.a);
	glVertex2f(x, y+h);
	glEnd();
}

void GL_GradientRect(float x, float y, float w, float h, GL_color_RGBA c1, GL_color_RGBA c2) {
	GL_color _c1 = GL_RGBA_to_Float(c1);
	GL_color _c2 = GL_RGBA_to_Float(c2);
	
	glBegin(GL_QUADS);
	glColor4f(_c1.r, _c1.g, _c1.b, _c1.a);
	glVertex2f(x, y);
	glVertex2f(x+w,y);
	glColor4f(_c2.r, _c2.g, _c2.b, _c2.a);
	glVertex2f(x+w, y+h);
	glVertex2f(x, y+h);
	glEnd();
}

void GL_Rotate(float rotation) {
}
